/*
 * $Id: XLI.cc,v 1.3 2006-02-10 04:08:35 bacon Exp $
 */

#include <xpp/xli/XLI.h>
#include <xpp/ScopedPtr.h>

namespace xpp
{
	namespace xli
	{

         	XLI::XLI (): _head(XP_NULL), _tail(XP_NULL) 
		{
		}

		XLI::~XLI ()
		{
			clear ();
		}

		void XLI::insert (const xp_char_t* k, const xp_char_t* v)
		{
			ScopedPtr<XLIKey>  key  (new XLIKey  (k));
			ScopedPtr<XLIStr>  val  (new XLIStr  (v));
			ScopedPtr<XLICell> cell (new XLICell (key.get(), val.get()));
		
			insert (cell.get());
		
			key.release ();
			val.release ();
			cell.release ();
		}
		void XLI::insert (const xp_char_t* k, XLIVal* val)
		{
			ScopedPtr<XLIKey>  key  (new XLIKey  (k));
			ScopedPtr<XLICell> cell (new XLICell (key.get(), val));
		
			insert (cell.get());
		
			key.release ();
			cell.release ();
		}
		
		void XLI::insert (XLIKey* key, XLIVal* val)
		{
			ScopedPtr<XLICell> cell (new XLICell (key, val));
			insert (cell.get());
			cell.release ();
		}
		
		void XLI::insert (XLICell* cell)
		{
			if (_head) {
				_tail->_cdr = cell;
				_tail = _tail->_cdr;
			}
			else {
				_head = cell;
				_tail = _head;
			}
		}
		
		/*
		void XLI::insert (const xp_char_t* k, const xp_char_t* v)
		{
			XLIStr* val = 0;
			try {
				val = new XLIStr (v);
				insert (k, val);
			}
			catch (...) {
				if (val) delete val;
				throw;
			}
		}
		
		void XLI::insert (const xp_char_t* k, XLIVal* val)
		{
			XLIKey* key = 0;
		
			try {
				key = new XLIKey (k);
				insert (key, val);
			}
			catch (...) {
				if (key) delete key;
				throw;
			}
		}
		void XLI::insert (XLIKey* key, XLIVal* val)
		{
			XLICell* cell = new XLICell (key, val);
		
			if (_head) {
				_tail->_cdr = cell;
				_tail = _tail->_cdr;
			}
			else {
				_head = cell;
				_tail = _head;
			}
		}
		*/
		
		
		int XLI::remove (const xp_char_t* k, xp_size_t idx)
		{
			XLICell* p = _head;
			XLICell* pp = 0;
			xp_size_t cnt = 0;
		
			while (p) {
				if (*(p->_key) == k) {
					if (idx == cnt) {
						if (pp) {
							if (!p->_cdr) _tail = pp;
							pp->_cdr = p->_cdr;
							delete p;
						}
						else {
							pp = _head;
							_head = _head->_cdr;
							if (!_head) _tail = 0;
							delete pp;
						}
						break;
					}
					cnt++;
				}
		
				pp = p;
				p = p->_cdr;
			}
		
			return -1;
		}
		
		int XLI::remove (XLIKey* key, xp_size_t idx)
		{
			return remove (key->_data, idx);
		}
		
		XLICell* XLI::findCell (const xp_char_t* k, xp_size_t idx) const
		{
			XLICell* p   = _head;
			xp_size_t     cnt = 0;
		
			while (p) {
				if (*(p->_key) == k) {
					if (idx == cnt) return p;
					cnt++;
				}
				p = p->_cdr;
			}
		
			return XP_NULL;
		}
		XLICell* XLI::findCell (XLIKey* key, xp_size_t idx) const
		{
			return findCell (key->_data, idx);
		}
		
		XLIVal* XLI::findVal (const xp_char_t* k, xp_size_t idx) const
		{
			XLICell* p = findCell (k, idx);
			return (p)? p->val(): XP_NULL;
		}
		XLIVal* XLI::findVal (XLIKey* key, xp_size_t idx) const
		{
			XLICell* p = findCell (key->_data, idx);
			return (p)? p->val(): XP_NULL;
		}
		
		xp_size_t XLI::getNkeys () 
		{
			XLICell* p   = _head;
			xp_size_t     cnt = 0;
		
			while (p) {
				cnt++;
				p = p->_cdr;
			}
		
			return cnt;
		}
		xp_size_t XLI::getNkeys (const xp_char_t* k)
		{
			XLICell* p = _head;
			xp_size_t cnt = 0;
		
			while (p) {
				if (*(p->_key) == k) cnt++;
				p = p->_cdr;
			}
		
			return cnt;
		}
		xp_size_t XLI::getNkeys (XLIKey* key)
		{
			return getNkeys (key->_data);
		}
		
		XLIVal* XLI::copy ()
		{
			/*
			XLI* xli = 0;
			try {
				xli = new XLI;
		
				XLICell* p = _head;
				while (p) {
					XLIVal* val = 0;
					try {
						val = p->_val->copy ();
						xli->insert (p->_key->_data, val);
					}
					catch (...) {
						if (val) delete val;
						throw;
					}
				
					p = p->_cdr;
				}
			}
			catch (...) {
				if (xli) delete xli;
				throw;
			}
			return xli;
			*/
		
		
			ScopedPtr<XLI> xliPtr (new XLI);
		
			XLICell* p = _head;
			while (p) {
				ScopedPtr<XLIVal> valPtr (p->_val->copy());
				xliPtr->insert (p->_key->_data, valPtr.get());
				valPtr.release ();
				p = p->_cdr;
			}
			
			return (XLIVal*)xliPtr.release();
		}
		
		void XLI::clear ()
		{
			XLICell* p = _head, * t;
			while (p) {
				t = p->_cdr;
				delete p;	
				p = t;
			}
		
			_head = _tail = 0;
		}
		
	}
}
